JavaScript精要之对象

1.定义属性

当一个属性第一次被添加给对象的时候,JavaScript在对象上调用了一个名为[[Put]]的内部方法。[[Put]]方法会在对象上创建一个新的节点来保存属性。此处创建的是自有属性,而不是原型属性。当一个已有属性,被赋予一个新的值的时候,调用[[Set]]方法。

2.属性探测

探测属性常见的错误:

1
2
3
if(person1.age){
do...
}

问题是:JavaScript的类型强制会影响其输出的结果。如果if判断的值是:一个对象、非空字符串、非0数字或者true时,判断为真;如果if判断的值是null、undefined、0、false、NaN或者空字符串的时候判断为假。

通过探测属性使用in和hasOwnProperty().

1
2
3
4
5
console.log("name" in person1);//true
console.log("toString" in person1);//true

console.log(person1 hasOwnProperty("name");//true
console.log(person1 hasOwnProperty("toString");//false

3.删除属性

注意:将一个属性值设置为null并不能从对象中彻底移除那个属性,只是调用了[[set]]这一内部方法,将属性值替换了而已。删除属性:delete。

1
delete person1.name;

4.属性枚举

两种方式:①for…in ②Object.keys()

示例:

for in 一般用于你不知道该数组或者JSON中包含哪些元素(还有就是对象中的哪些属性),而进行遍历。(key的值就相当于下标)
例如有一个元素未知的JSON对象:

1
2
3
4
5
var clnums = {a:1,b:2,...};
var key;
for(key in clnums){
document.write(clnums[key]);
}

如果你只需获取一个对象的属性列表,以备程序将来使用。可以使用Object.keys()方法:

1
2
3
4
5
6
var zs = Object.keys(object);
var i;
for(i=0;i<zs.length;i++){
console.log("name:"+zs[i]);
console.log("value:"+object[zs]);
}

Console显示如下:

*注意:并不是所有的属性都是可以枚举的。实际上,大部分的原生方法的[[Enumerable]]都被设置成了false。可以使用propertyIsEnumerable()方法来检测属性是否是可以枚举的。

1
2
3
4
5
6
7
8
var person1 ={
name:“Cooling”
};
console.log(person1.propertyIsEnumerable("name"));//true

var zs = Object.keys(person1);
console.log("length" in zs);
console.log(zs.propertyIsEnumerable("length");//false内建属性不可枚举,因此zs是不存在的

5.属性类型

属性分为两种:++数据属性、访问器属性++。[[put]]方法默认创建的是数据属性,如前面的name、age属性等。

访问器属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var person1 = {
_name: "Cooling"
get name(){
console.log("Reading name");
return this._name;
},
set name(value){
console.log("Setting name to %s",value);
this._name = value;
};
console.log(person1.name);

person1.name = "zs";
console.log(person1.name);

注释:本例定义了一个访问器属性name。一个数据属性_name保存了访问器属性的实际值。(下划线是一个约定俗成的规范,表示该属性是被私有的,实际上它还是公开的)。读取时调用的函数称为getter,写入时调用的函数称为setter。如果只定义其中一个函数,那么,其属性将会是只读或者是只写的。

6.属性特征

6.1通用特征:

通用属性有两个:[[Enumerable]](表示是否可以枚举,也就是是否可以遍历)、[[Configurable]](表示是否可以配置)。你所声明的所有属性都是可以枚举、可以配置的。如果想对一个属性进行设置是否可以枚举和配置(方法:Object.defineProperty()),可以如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var person1 = {
name:"Cooling"
};
Object.defineProperty(person1,"name",{
Enumerable:false
});
console.log(person1.propertyIsEnumerable("name");//false
var zs = Object.keys(person1);
console.log(zs.length);//0


Object.defineProperty(person1,"name",{
configurable:false;
});
delete person.name;
console.log(person1.name);//Cooling
Object.defineProperty(person1,"name",{
confingurable:true;
}); //error!!!

6.2数据属性的特征

数据属性具有两个访问器属性不具有的特征。即:[[Value]]、[[Writable]].
实例:(当Object.defineProperty()被调用时,会先检测属性是否存在,如果不存在,则根据所给定的特征创建。)

1
2
3
4
5
6
7
var person1 = {};
Object.defineProperty(person1,"name",{
value:"cooling",
enumerable:true,
configurable:true,
writable:true
});

当你使用Object.defineProperty()定义新的属性的时候,一定要注意为所有的特征指定一个值,否则布尔型的特征值会被默认设置为false。如:

1
2
3
4
5
6
7
8
9
10
var person1 = {};
Object.defineProperty(person1,"name",{
value:"cooling";
});
console.log("name" in person1);//true
console.log(person1.propertyIsEnumerable("name")//false
delete person1.name;
console.log(person1.name);//cooling
person1.name = "zs";
console.log(person1.name);//cooling

温馨提示:数据属性可以通过writable来设置属性是否可以被写。而在访问器属性中,可以通过setter和getter设置!

6.3访问器属性的特征

也具有两个额外的特征:[[Get]]、[[Set]]。仅仅需要定义其中一个特征就可以创建一个访问器属性。

注意:不能同时创建一个具有数据属性特征和访问器属性特征的属性。

可以将前面的改写:

1
2
3
4
5
6
7
8
9
10
var person1 = {
_name: "Cooling"
get name(){
console.log("Reading name");
return this._name;
},
set name(value){
console.log("Setting name to %s",value);
this._name = value;
};

改写后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var person1 = {
_name: "Cooling"
};
Object.defineproperty(person1,"name",{
get function(){//注意改变
console.log("Reading name");
return this._name;
},
set function(value){//注意改变
console.log("Setting name to %s",value);
this._name = value;
},
enumerable: true,
configurable:true
});
//注意:跟数据属性类似,如果这里的enumerable: true和configurable:true都不写的话,那么,就默认为false。这样就只能读取属性,不能改变属性。

6.4定义多重属性
使用方法:Object.defineProperties();
使用示例:(定义了_name数据属性和name访问器属性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var person1 = {};
Object.defineProperties(person1,{
_name:{
value:"cooling",
enumerable:true,
configurable:true,
writable:true
},
name:{
get:function(){
console.log("Reading name");
return this.name;
},
set:function(value){
console.log("Setting name to %s",value);
},
enumerable:true,
configurable:true,
}
});

6.5获取属性的特征
方法:Object.getOwnPropertyDescriptor();

1
2
3
4
5
6
var person1 = {
name: "cooling"
};
var descipt = Object.getOwnPropertyDesciptor(person1,"name");
console.log(descipt.enumerable);//true
console.log(descipt.configurable);//true

温馨提示:要特别注意使用Object.defineProperty()定义属性和直接var person1 = {name:”cooling”};这样定义的区别。他俩一个属性特征是完全不一样的!

7.禁止修改对象

对象和属性一样都具有指导其行为的内部特征。其中,[[Extensible]]就是一个,值为布尔类型的,表示是否可以扩展,也就是是否可以为对象添加属性。

有三种方式禁止修改对象:

①禁止扩展(不可添加属性,可以对属性值进行修改,同时也可以删除属性值)

【注:[[Extensible]]为false】

方法:Object.preventExtensions();

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
var person1 = {
name:"cooling";
};
console.log(Object.isExtensible(person1));//true

Object.preventExtensions(person1);
console.log(Object.isExtensible(person1);//false

person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false

②对象封印(不可添加属性、可以对属性值进行修改,但是不能删除属性值)

【注:[[Extensible]]:flase [[Configurable]]:false】

方法:Object.seal();

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var person1 = {
name:"cooling"
};
console.log(Object.isExtensible(person1));//true
console.log(Object.isSealed(person1));//false

Object.seal(person1);
console.log(Object.isExtensible(person1));//false
console.log(Object.isSealed);//true

person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false
person1.name = "zs";
console.log(person1.name)//zs
delete person1.name;
console.log("name" in person1);//true
console.log(person1.name)//zs

var de = Object.getOwnPropertyDescriptor(person1,"name");
console.log(de.configurable);//false

③对象冻结(不可添加属性,不可对属性进行修改,不能写入数据)

【注:[[Configurable]]:false [[Writable]]:false [[Extensible]]:false】

方法:Object.freeze();

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var person1 = {
name:"cooling";
};
console.log(Object.isExtensible(person1));//true
console.log(Object.isSealed(person1));//false
console.log(Object.isFrozen);//false

Object.freeze(person1);
console.log(Object.isExtensible(person1));//false
console.log(Object.isSealed(person1));//true
console.log(Object.isFrozen);//true

person1.sayName = function(){
console.log(this.name);
};
console.log("sayName" in person1);//false

person1.name = "zs";
console.log(person1.name);//cooling
var de = Object.getOwnPropertyDescriptor(person1,"name");
console.log(de.configurable);//false
console.log(de.writable);//false